package com.industrial.auth.controller;

import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.industrial.auth.controller.response.TokenFromData;
import com.industrial.auth.controller.response.UserInfo;
import com.industrial.auth.controller.response.company.CompanyInfo;
import com.industrial.auth.controller.response.company.CompanyRecords;
import com.industrial.auth.controller.response.company.CompanyRecordsDto;
import com.industrial.auth.controller.response.company.CompanyTableResp;
import com.industrial.auth.controller.response.corporation.Corporation;
import com.industrial.auth.controller.response.coruser.Coruser;
import com.industrial.auth.controller.response.coruser.CoruserResp;
import com.industrial.auth.controller.response.sdt.SdtAccessTokenResp;
import com.industrial.auth.controller.response.sdt.SdtUserInfoResp;
import com.industrial.auth.controller.response.user.UserInfoRes;
import com.industrial.auth.form.LoginBody;
import com.industrial.auth.service.IdentityAuthenticationService;
import com.industrial.auth.zhgx.oauth2.model.OupAuth2Token;
import com.industrial.auth.zhgx.oauth2.model.OupAuth2TokenDto;
import com.industrial.auth.zhgx.oauth2.model.OupAuth2TokenUserInfo;
import com.industrial.auth.zhgx.oauth2.properties.Oauth2Properties;
import com.industrial.common.core.constant.SdAuthenticationApi;
import com.industrial.common.core.constant.SecurityConstants;
import com.industrial.common.core.domain.R;
import com.industrial.common.core.enums.UserStatus;
import com.industrial.common.core.exception.ServiceException;
import com.industrial.common.core.utils.StringUtils;
import com.industrial.common.security.service.TokenService;
import com.industrial.system.api.RemoteUserService;
import com.industrial.system.api.domain.BizAccountMapping;
import com.industrial.system.api.domain.SysUser;
import com.industrial.system.api.model.LoginUser;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 山东省统一认证平台
 * @author sd
 */
@RestController
@RequestMapping("/cnm")
public class IdentityAuthenticationController {

    private static final Logger log = LoggerFactory.getLogger(IdentityAuthenticationController.class);

    private final IdentityAuthenticationService identityAuthenticationService;

    private final CloseableHttpClient closeableHttpClient;

    private RemoteUserService remoteUserService;


    private TokenService tokenService;

    private final ObjectMapper objectMapper;

    private final Oauth2Properties oauth2Properties;

    public IdentityAuthenticationController(IdentityAuthenticationService identityAuthenticationService, CloseableHttpClient closeableHttpClient, ObjectMapper objectMapper, Oauth2Properties oauth2Properties, RemoteUserService remoteUserService, TokenService tokenService) {
        this.identityAuthenticationService = identityAuthenticationService;
        this.closeableHttpClient = closeableHttpClient;
        this.objectMapper = objectMapper;
        this.oauth2Properties = oauth2Properties;
        this.remoteUserService = remoteUserService;
        this.tokenService = tokenService;
    }

    /**
     * 山东省身份认证平台回调接口
     * @param ticket 票据
     * @return
     */
    @GetMapping("/callback")
    public R<?> callBack(@RequestParam(value = "ticket",required = true) String ticket){
        log.error("ticket:{}",ticket);
        HttpPost httpPost = new HttpPost(String.format(SdAuthenticationApi.GET_TOKEN_BY_TICKET,ticket));
        JSONObject ticketBody = new JSONObject();
//        ticketBody.put("ticket",ticket);
        //增加一些额外的参数
        JSONObject sendPostParams = parameter(ticketBody);
        StringEntity ticketEntity = new StringEntity(sendPostParams.toJSONString(),"UTF-8");
        httpPost.setHeader("Accept","application/json");
        httpPost.setEntity(ticketEntity);
        try(CloseableHttpResponse response = closeableHttpClient.execute(httpPost)){
            int statusCode = response.getStatusLine().getStatusCode();
            log.error("获取Token状态:{}",statusCode);
            String responseStr = EntityUtils.toString(response.getEntity());
            if(StringUtils.isBlank(responseStr)){
                return R.fail("获取Token失败");
            }
            log.error("工信返回的数据:{}",responseStr);
            if(statusCode == 200){
                TokenFromData tokenFromTicketResp = JSONObject.parseObject(responseStr, TokenFromData.class);
                UserInfo userInfo = tokenFromTicketResp.getData().getUserInfo();
                log.error("userInfo:{}",userInfo);
                if(userInfo != null && StringUtils.equals("2",userInfo.getUsertype())){
                    log.error("用户ID:{}",userInfo.getId());
                    //如果是法人登陆，获取法人名下所有的企业
                    HttpGet httpGet = new HttpGet(SdAuthenticationApi.GET_CORPORATION_BY_CORUSER);
                    httpGet.setHeader("Authorization","Bearer " + String.valueOf(tokenFromTicketResp.getData().getAccessToken()));

                    try(CloseableHttpResponse companyRes = closeableHttpClient.execute(httpGet)){
                        int companyResStatus = companyRes.getStatusLine().getStatusCode();
                        String companyResResult = EntityUtils.toString(companyRes.getEntity());

                        CompanyTableResp companyTableResp = JSONObject.parseObject(companyResResult, CompanyTableResp.class);

                        log.error("企业列表数据：{}，状态:{}",companyResResult,companyResStatus);
                        if(companyResStatus == 200){
                            CompanyRecords data = companyTableResp.getData();
                            if(data != null){
                                List<CompanyInfo> records = data.getRecords();
                                if(records != null && !records.isEmpty()){
                                    List<CompanyInfo> collect = records.stream().map(item -> {
                                        item.setToken(tokenFromTicketResp.getData().getAccessToken());
                                        item.setUserType("2");
                                        return item;
                                    }).collect(Collectors.toList());
                                    data.setRecords(collect);
                                    companyTableResp.setData(data);
                                }
                            }
                            log.error("企业列表数据：{}",companyResResult);
                            return R.ok(companyTableResp.getData());
                        }else{
                            return R.fail(companyTableResp.getMsg());
                        }
                    }catch (Exception e){
                        return R.fail("获取企业列表失败:{}",e.toString());
                    }
                }else if(userInfo != null && StringUtils.equals("0",userInfo.getUsertype())){
                    //厅内人员登陆，直接返回列表
                    List<CompanyInfo> p = new ArrayList<>();
                    CompanyInfo c = new CompanyInfo();
                    c.setCorname(userInfo.getZwfwUuid());
                    c.setCornumber(userInfo.getUsername());
                    c.setToken(tokenFromTicketResp.getData().getAccessToken());
                    c.setUserType("0");
                    p.add(c);

                    CompanyRecords companyRecords = new CompanyRecords();
                    companyRecords.setRecords(p);

                    CompanyTableResp temp = new CompanyTableResp();
                    temp.setCode(200);
                    temp.setMsg("查询成功");
                    temp.setData(companyRecords);
                    return R.ok(temp.getData());
                }else if(userInfo != null && StringUtils.equals("1",userInfo.getUsertype())){
                    return R.fail("请使用法人账号登陆");
                }
                return R.fail("没有获取到省认证平台中的用户Id");
            }else{
                return R.fail("登陆失败:" + responseStr);
            }

        }catch (Exception e){
            return R.fail(String.format("登陆失败:%s",e.getMessage()));
        }
    }

    /**
     * 新版智慧工信对接接口
     */
    @GetMapping("/callbackNew")
    public R<?> callBackNew(@RequestParam(value = "code") String code) throws IOException {

        String getTokenUrl = UriComponentsBuilder.fromUriString(oauth2Properties.getTokenUrl())
                .queryParam("grant_type", "authorization_code")
                .queryParam("client_id", oauth2Properties.getAppId())
                .queryParam("client_secret", oauth2Properties.getAppSecret())
                .queryParam("redirect_uri", URLEncoder.encode(oauth2Properties.getRedirectUrl(), "UTF-8"))
                .queryParam("code", code)
                .build()
                .toUriString();

        HttpGet httpGet = new HttpGet(getTokenUrl);
        try (CloseableHttpResponse tokenRes = closeableHttpClient.execute(httpGet)) {
            int statusCode = tokenRes.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                String tokenResResult = EntityUtils.toString(tokenRes.getEntity());
                OupAuth2Token oupAuth2Token = objectMapper.readValue(tokenResResult, OupAuth2Token.class);
                String accessToken = oupAuth2Token.getAccessToken();
                OupAuth2TokenUserInfo userInfo = oupAuth2Token.getUserInfo();
                if (userInfo != null && StringUtils.equals("2", userInfo.getUserType())) {
                    // 如果是法人登陆，获取该法人名下的企业信息
                    HttpGet httpGet1 = new HttpGet(oauth2Properties.getUserInfoUrl());
                    httpGet1.setHeader("Authorization", "Bearer " + accessToken);

                    try (CloseableHttpResponse userInfoRes = closeableHttpClient.execute(httpGet1)) {
                        int userInfoResStatus = userInfoRes.getStatusLine().getStatusCode();
                        String userInfoResResult = EntityUtils.toString(userInfoRes.getEntity());

                        UserInfoRes userInfoResp = JSONObject.parseObject(userInfoResResult, UserInfoRes.class);

                        log.error("userInfo：{}", userInfoResp);
                        if (userInfoResStatus == 200) {
                            com.industrial.auth.controller.response.user.UserInfo data = userInfoResp.getData();
                            if(data != null) {
                                Corporation corporation = data.getCorporation();
                                if(corporation != null) {
                                    CompanyInfo companyInfo = new CompanyInfo();
                                    companyInfo.setCornumber(corporation.getCorCode());
                                    companyInfo.setCorname(corporation.getCorName());
                                    companyInfo.setToken(accessToken);
                                    companyInfo.setUserType("2");
                                    List<CompanyInfo> list = Arrays.asList(companyInfo);
                                    CompanyRecordsDto companyRecords = new CompanyRecordsDto();
                                    companyRecords.setRecords(list);
                                    companyRecords.setUserInfo(userInfo);
                                    log.error("返回结果为：{}", companyRecords);
                                    return R.ok(companyRecords);
                                } else {
                                    return R.fail("获取企业数据失败");
                                }
                            } else {
                                return R.fail("获取企业数据失败");
                            }
                        } else {
                            return R.fail("获取企业数据失败");
                        }
                    } catch (Exception e) {
                        return R.fail("获取企业数据失败:{}", e.toString());
                    }
                } else if (userInfo != null && StringUtils.equals("0", userInfo.getUserType())) {
                    // 厅内人员登陆，直接返回列表
                    List<CompanyInfo> p = new ArrayList<>();
                    CompanyInfo c = new CompanyInfo();
                    c.setCorname(userInfo.getZwfwUuid());
                    c.setCornumber(userInfo.getUsername());
                    c.setToken(accessToken);
                    c.setUserType("0");
                    p.add(c);

                    CompanyRecordsDto companyRecords = new CompanyRecordsDto();
                    companyRecords.setRecords(p);
                    companyRecords.setUserInfo(userInfo);

                    return R.ok(companyRecords);
                } else if (userInfo != null && StringUtils.equals("1", userInfo.getUserType())) {
                    return R.fail("请使用法人账号登陆");
                }
                return R.fail("认证失败");
            } else {
                return R.fail("认证失败");
            }
        } catch (Exception e) {
            return R.fail(e.getMessage());
        }
    }

    @PostMapping("qwwqplvdng")
    public R<?> login(@RequestBody LoginBody form){

        if(StringUtils.isBlank(form.getUsername()) || StringUtils.isBlank(form.getToken())){
            return R.fail("没有找到用户名或Token");
        }

        if(!(StringUtils.equals("0",form.getUserType()) || StringUtils.equals("2",form.getUserType()))){
            return R.fail("非法状态异常");
        }


        HttpGet httpGet = null;
        //法人登陆
        if(StringUtils.equals("2",form.getUserType())){
            httpGet = new HttpGet(SdAuthenticationApi.GET_CORUSER_BY_TOKEN);
        } else if (StringUtils.equals("0",form.getUserType())) {
            httpGet = new HttpGet(SdAuthenticationApi.GET_TINGNEI_BY_TOKEN);
        }else{
            return R.fail("非法状态异常");
        }

        httpGet.setHeader("Authorization","Bearer " + form.getToken());
        try(CloseableHttpResponse companyRes = closeableHttpClient.execute(httpGet)){
            int statusCode = companyRes.getStatusLine().getStatusCode();
            if(statusCode == 200){
                String corUserResResult = EntityUtils.toString(companyRes.getEntity());
                CoruserResp coruserResp = JSONObject.parseObject(corUserResResult, CoruserResp.class);
                Coruser data = coruserResp.getData();

                if(StringUtils.isBlank(data.getUuid())){
                    data.setUuid(data.getUserId());
                }

                if(StringUtils.isBlank(data.getLoginname())){
                    data.setLoginname(data.getUsername());
                }

                if(data == null || StringUtils.isBlank(data.getUuid()) || StringUtils.isBlank(data.getLoginname())){
                    return R.fail("获取登陆人信息失败");
                }

                //远程调用查询关联信息，如果没有插入关联信息，则反回已关联的信息
                R<Map<String, Object>> mapR = remoteUserService.selectSuserToBizUser(data.getUuid(), form.getUsername());
                if(mapR.getCode() == R.SUCCESS){
                    Map<String, Object> data1 = mapR.getData();
                    String bizUserId = (String)data1.get("bizUserId");
                    if(StringUtils.isBlank(bizUserId)){
                        return R.fail(mapR.getMsg());
                    }
                    // 查询用户信息
                    R<LoginUser> userResult = remoteUserService.getUserInfo(form.getUsername(), SecurityConstants.INNER);

                    log.error("userResult:{}",JSONObject.toJSONString(userResult));

                    if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
                    {
                        throw new ServiceException("没有找到【" + form.getUsername() + "】用户");
                    }

                    if (R.FAIL == userResult.getCode())
                    {
                        throw new ServiceException(userResult.getMsg());
                    }

                    LoginUser userInfo = userResult.getData();

                    SysUser user = userResult.getData().getSysUser();
                    if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
                    {
                        throw new ServiceException("对不起，您的账号：" + form.getUsername() + " 已被删除");
                    }
                    if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
                    {
                        throw new ServiceException("对不起，您的账号：" + form.getUsername() + " 已停用");
                    }

                    return R.ok(tokenService.createToken(userInfo));
                }else{
                    return R.fail(mapR.getMsg());
                }
            }else{
                return R.fail("获取登陆人信息失败");
            }
        }catch (Exception e){
            return R.fail(e.getMessage());
        }
    }

    /**
     * 新版智慧工信对接 - 授权登录接口
     */
    @PostMapping("qwwqplvdngNew")
    public R<?> loginNew(@RequestBody OupAuth2TokenDto dto) throws IOException {

        OupAuth2TokenUserInfo tokenUserInfo = dto.getUserInfo();
        String zwfwUuid = null;
        String username = null;
        if (tokenUserInfo != null) {
            zwfwUuid = tokenUserInfo.getZwfwUuid();
            username = dto.getCorCode();
            int id = tokenUserInfo.getId();
            if (StringUtils.isBlank(zwfwUuid)) {
                zwfwUuid = id + "";
            }

            if (StringUtils.isBlank(username)) {
                username = tokenUserInfo.getUsername();
            }

            if (StringUtils.isBlank(zwfwUuid) || StringUtils.isBlank(username)) {
                return R.fail("获取登陆人信息失败");
            }
        } else {
            return R.fail("获取登陆人信息失败");
        }

        //远程调用查询关联信息，如果没有插入关联信息，则反回已关联的信息
        R<Map<String, Object>> mapR = remoteUserService.selectSuserToBizUser(zwfwUuid, username);
        if (mapR.getCode() == R.SUCCESS){
            Map<String, Object> data1 = mapR.getData();
            String bizUserId = (String)data1.get("bizUserId");
            if (StringUtils.isBlank(bizUserId)){
                return R.fail(mapR.getMsg());
            }
            // 查询用户信息
            R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER);

            log.error("userResult:{}",JSONObject.toJSONString(userResult));

            if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
            {
                throw new ServiceException("没有找到【" + username + "】用户");
            }

            if (R.FAIL == userResult.getCode())
            {
                throw new ServiceException(userResult.getMsg());
            }

            LoginUser userInfo = userResult.getData();

            SysUser user = userResult.getData().getSysUser();
            if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
            {
                throw new ServiceException("对不起，您的账号：" + username + " 已被删除");
            }
            if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
            {
                throw new ServiceException("对不起，您的账号：" + username + " 已停用");
            }

            return R.ok(tokenService.createToken(userInfo));
        } else {
            return R.fail(mapR.getMsg());
        }
    }

    /**
     * 加入必传参数
     * @param jsonObject
     * @return
     */
    private JSONObject parameter(JSONObject jsonObject){
        //用户的唯一标识
        jsonObject.put("app_id","");
        //服务名称
        jsonObject.put("servicename", "ticketValidate");
        return jsonObject;
    }


    //*********************************************
    //************                     ************
    //************      山东通登陆       ************
    //************                     ************
    //*********************************************

    @PostMapping("/shanDongTongLogin")
    public R<?> shanDongTongLogin(@RequestBody Map<String,String> params){
        String code = params.get("code");
        if(StringUtils.isBlank(code)){
            return R.fail("没有找到标识参数");
        }

        //获取访问Token
        String accessToken = getAccessToken();
        log.error("shanDongTongLogin的accessToken:{}",accessToken);
        if(StringUtils.isBlank(accessToken)){
            return R.fail("获取token失败");
        }

        //获取用户信息
        HttpGet httpGet = new HttpGet(String.format(SdAuthenticationApi.SDT_GET_USER_INFO,accessToken,code));
        try(CloseableHttpResponse userInfoRes = closeableHttpClient.execute(httpGet)){

            //该状态为200只能说明是请求成功，但是不能代表业务数据正常
            if(userInfoRes.getStatusLine().getStatusCode() == HttpStatus.OK.value()) {
                String userInfoEntityJson = EntityUtils.toString(userInfoRes.getEntity());
                SdtUserInfoResp sdtUserInfoResp = JSONObject.parseObject(userInfoEntityJson, SdtUserInfoResp.class);
                //如果业务状态码不为0，就是获取用户信息失败
                if(!StringUtils.equals(sdtUserInfoResp.getErrCode(),"0")){
                    return R.fail(sdtUserInfoResp.getErrMsg());
                }
                //获取出山东通统一用户编码
                String userId = sdtUserInfoResp.getUserId();
                if(StringUtils.isBlank(userId)){
                    return R.fail("没有找到山东通用户Id");
                }
                System.out.println("山东通用户Id:" + userId);
                //查询业务库中用户是否和山东通用户绑定
                R<LoginUser> loginUserR = remoteUserService.querySdtUserBingBizUserStatus(userId);
                if(loginUserR.getCode() == R.SUCCESS){
                    LoginUser loginUser = loginUserR.getData();
                    if(loginUser == null){
                        Map<String, Object> errInfo = new HashMap<>(16);
                        errInfo.put("token","");
                        errInfo.put("msg","没有找到用户绑定关系");
                        errInfo.put("sPtUserId",userId);
                        return R.ok(errInfo);
                    }else{
                        Map<String, Object> token = tokenService.createToken(loginUser);
                        System.out.println("获取到的token:" + (token == null ? "没有取到" : token.get("token")));
                        return R.ok(token);
                    }
                }else{
                    return R.fail("登陆失败");
                }
            }else{
                return R.fail("未找到用户信息");
            }
        }catch (Exception e){
            e.printStackTrace();
            return R.fail(e.getMessage());
        }
    }

    @PostMapping("/bind")
    public R<?> sdtUserBindBizUser(@RequestBody BizAccountMapping sysUser){
        if(StringUtils.isBlank(sysUser.getBizUserPwd()) || StringUtils.isBlank(sysUser.getBizUserName()) || StringUtils.isBlank(sysUser.getsPtUserId())){
            return R.fail("请填写用户名或密码");
        }
        R<LoginUser> loginUserR = remoteUserService.sdtUserBindBizUser(sysUser);
        if(loginUserR.getCode() == R.SUCCESS){
            LoginUser data = loginUserR.getData();
            if(data ==null){
                return R.fail("绑定失败,用户数据为空");
            }
            return R.ok(tokenService.createToken(data));
        }else{
            return R.fail(loginUserR.getMsg());
        }
    }


    private String getAccessToken() {
        //获取ACCESS_TOKEN
        String accessToken = "";
        HttpGet httpGet = new HttpGet(SdAuthenticationApi.SDT_ACCESS_TOKEN);

        try(CloseableHttpResponse companyRes = closeableHttpClient.execute(httpGet)){
            int statusCode = companyRes.getStatusLine().getStatusCode();
            if(statusCode == HttpStatus.OK.value()){
                String tokeJsonStr = EntityUtils.toString(companyRes.getEntity());
                SdtAccessTokenResp sdtAccessTokenResp = JSONObject.parseObject(tokeJsonStr, SdtAccessTokenResp.class);
                if(sdtAccessTokenResp.getErrCode() == 0){
                    return sdtAccessTokenResp.getAccessToken();
                }else{
                    log.error("错误信息:{}", sdtAccessTokenResp.getErrMsg());
                }
                return accessToken;
            }else{
                log.error("请求获取Token的状态码为：{}" , statusCode);
            }
            return accessToken;
        }catch (Exception e){
            log.error("获取山东通Token失败");
            e.printStackTrace();
            return accessToken;
        }
    }

}
